<?php
class Misc
{
    public static function XMLToArray($xml, $get_attributes=true)
    {/*{{{*/
        $parser=xml_parser_create('');
        xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING,
                "UTF-8");
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
        xml_parse_into_struct($parser, trim($xml), $xml_values);
        xml_parser_free($parser);
        if(is_null($xml_values))
            return false;

        $xml_array=array();
        $parents=array();
        $opened_tags=array();
        $arr=array();
        $current=&$xml_array;
        $repeated_tag_index=array();
        foreach($xml_values as $data)
        {
            $result='';
            $attributes_data=array();
            if(isset($data['value']))
            {
                $value=$data['value'];
                $result=$value;
            }
            if(isset($data['attributes']) && $get_attributes)
            {
                $attributes=$data['attributes'];
                foreach($attributes as $attr=>$val)
                {
                    $attributes_data[$attr]=$val;
                }
            }
            $type=$data['type'];
            $level=$data['level'];
            $tag=$data['tag'];
            if($type == "open")
            {
                $parents[$level-1]=&$current;
                if(!is_array($current) ||
                        !in_array($tag, array_keys($current)))
                {
                    $current[$tag]=$result;
                    if($get_attributes)
                        $current[$tag.'_attr']=$attributes_data;
                    $repeated_tag_index[$tag.'_'.$level]=1;
                    $current=&$current[$tag];
                }
                else
                {
                    if(isset($current[$tag][0]))
                    {
                        $current[$tag][$repeated_tag_index
                            [$tag.'_'.$level]]=$result;
                        $repeated_tag_index[$tag.'_'.$level]++;
                    }
                    else
                    {
                        $current[$tag]=array($current[$tag], $result);
                        $repeated_tag_index[$tag.'_'.$level]=2;
                        if(isset($current[$tag.'_attr']))
                        {
                            $current[$tag]['0_attr']=
                                $current[$tag.'_attr'];
                            unset($current[$tag.'_attr']);
                        }
                    }
                    $last_item_index=
                        $repeated_tag_index[$tag.'_'.$level]-1;
                    $current=&$current[$tag][$last_item_index];
                }
            }
            elseif($type == "complete")
            {
                if(!isset($current[$tag]))
                {
                    $current[$tag]=$result;
                    $repeated_tag_index[$tag.'_'.$level]=1;
                    if($get_attributes)
                        $current[$tag.'_attr']=$attributes_data;
                }
                else
                {
                    if(isset($current[$tag][0]) &&
                            is_array($current[$tag]))
                    {
                        $current[$tag][$repeated_tag_index
                            [$tag.'_'.$level]]=$result;
                        if ($get_attributes)
                        {
                            $current[$tag][$repeated_tag_index
                                [$tag.'_'.$level].'_attr']=
                                $attributes_data;
                        }
                        $repeated_tag_index[$tag.'_'.$level]++;
                    }
                    else
                    {
                        $current[$tag]=array($current[$tag], $result);
                        $repeated_tag_index[$tag.'_'.$level]=1;
                        if ($get_attributes)
                        {
                            if(isset($current[$tag.'_attr']))
                            {
                                $current[$tag]['0_attr']=
                                    $current[$tag.'_attr'];
                                unset($current[$tag.'_attr']);
                            }
                            $current[$tag][$repeated_tag_index
                                [$tag.'_'.$level].'_attr']=
                                $attributes_data;
                        }
                        //0 and 1 index is already taken
                        $repeated_tag_index[$tag.'_'.$level]++;
                    }
                }
            }
            elseif($type == 'close')
            {
                $current=&$parents[$level-1];
            }
        }
        return ($xml_array);
    }/*}}}*/

    public static function XMLToArray2($xml)
    {/*{{{*/
        $xmlObj=simplexml_load_string($xml);
        return self::objectsIntoArray($xmlObj);
    }/*}}}*/

    private static function objectsIntoArray($arrObjData,
            $arrSkipIndices = array())
    {/*{{{*/
        $arrData=array();

        // if input is object, convert into array
        if (is_object($arrObjData))
        {
            $arrObjData=get_object_vars($arrObjData);
        }

        if (is_array($arrObjData))
        {
            foreach ($arrObjData as $index=>$value)
            {
                if(is_object($value) || is_array($value))
                {
                    $value=self::objectsIntoArray($value, $arrSkipIndices);
                }
                if(in_array($index, $arrSkipIndices))
                {
                    continue;
                }
                $arrData[$index]=$value;
            }
        }
        return $arrData;
    }/*}}}*/
}

$xml=<<<EOD
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <son name="Jack">
        <grandson name="Tom">hello</grandson>
        <granddaughter name="Mary">Hi</granddaughter>
    </son>
    <son name="Michael">hello</son>
    <son name="John">
        <grandson name="Colin">hi</grandson>
    </son>
</root>
EOD;
$arr=Misc::XMLToArray($xml, true);
print_r($arr);

$xml=<<<EOD
<?xml version="1.0" encoding="UTF-8"?>
<root>
    <name>A</name>
    <child>
        <name>Jack</name>
        <child>
            <name>Tom</name>
            <age>10</age>
        </child>
    </child>
    <child>
        <name>Michael</name>
    </child>
</root>
EOD;
$arr=Misc::XMLToArray($xml, false);
print_r($arr);

if(is_string($arr['root']['child'][0]['child']['age']))
{
    print "is string\n";
}
else
{
    print "is not string\n";
}
?>
